/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs     (C)ChaN, 2019        */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be        */
/* attached to the FatFs via a glue function rather than modifying it.   */
/* This is an example of glue functions to attach various exsisting      */
/* storage control modules to the FatFs module with a defined API.       */
/*-----------------------------------------------------------------------*/
#include <stdio.h>
#include "ff.h"			/* Obtains integer types */
#include "diskio.h"		/* Declarations of disk functions */
#include "../bsp_w25q64.h"

#define DEV_SPI_FLASH       0

#define SECTOR_SIZE         4096

/*-----------------------------------------------------------------------*/
/* Get Drive Status                                                      */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
	BYTE pdrv		/* Physical drive nmuber to identify the drive */
)
{
	return RES_OK;
}



/*-----------------------------------------------------------------------*/
/* Inidialize a Drive                                                    */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
	BYTE pdrv				/* Physical drive nmuber to identify the drive */
)
{
    if (pdrv == DEV_SPI_FLASH) {
        spi_port_init();
    }
    
	return RES_OK;
}



/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/

DRESULT disk_read (
	BYTE pdrv,		/* Physical drive nmuber to identify the drive */
	BYTE *buff,		/* Data buffer to store read data */
	LBA_t sector,	/* Start sector in LBA */
	UINT count		/* Number of sectors to read */
)
{
    if (pdrv == DEV_SPI_FLASH) {
        uint32_t addr = sector * SECTOR_SIZE;
        
        for (int i = 0; i < count; i++) {
            W25Q64_read_sector(buff, addr, SECTOR_SIZE); 
            addr += SECTOR_SIZE;
            buff += SECTOR_SIZE;
        }
        return RES_OK;
        
    }
    
	return RES_PARERR;
}



/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/

#if FF_FS_READONLY == 0

DRESULT disk_write (
	BYTE pdrv,			/* Physical drive nmuber to identify the drive */
	const BYTE *buff,	/* Data to be written */
	LBA_t sector,		/* Start sector in LBA */
	UINT count			/* Number of sectors to write */
)
{
    if (pdrv == DEV_SPI_FLASH) {
        uint32_t addr = sector * SECTOR_SIZE;
        
        for (int i = 0; i < count; i++) {
            W25Q64_erase_sector(addr);
            W25Q64_write_sector((uint8_t*)buff, addr, SECTOR_SIZE); 
            addr += SECTOR_SIZE;
            buff += SECTOR_SIZE;
        }
        return RES_OK;
        
    }
    
	return RES_PARERR;}

#endif


/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/

DRESULT disk_ioctl (
	BYTE pdrv,		/* Physical drive nmuber (0..) */
	BYTE cmd,		/* Control code */
	void *buff		/* Buffer to send/receive control data */
)
{
    if (pdrv == DEV_SPI_FLASH) {
        switch (cmd) {
            case CTRL_SYNC:
                return RES_OK;
            case GET_SECTOR_COUNT: {
                *(DWORD *)buff = 2048;
                return RES_OK;
            }
            case GET_SECTOR_SIZE: {
                *(WORD *)buff = SECTOR_SIZE;
                return RES_OK;
            }
        }
    }
    
	return RES_PARERR;
}

DWORD get_fattime(void) {
	return (DWORD)(2022 - 80) << 25 |
		(DWORD)(3 + 1) << 21 |
		(DWORD)1 << 16 |
		(DWORD)0 << 11 |
		(DWORD)0 << 5 |
		(DWORD)0 >> 1;
}


